package com.gitee.deeround.jdbchelper.impl;

import com.gitee.deeround.jdbchelper.DbAction;
import com.gitee.deeround.jdbchelper.DbActionConfig;
import com.gitee.deeround.jdbchelper.core.*;
import com.gitee.deeround.jdbchelper.core.impl.*;
import com.gitee.deeround.jdbchelper.exception.DbException;
import com.gitee.deeround.jdbchelper.in.SqlParameter;
import com.gitee.deeround.jdbchelper.out.DataTable;
import com.gitee.deeround.jdbchelper.out.DbColumn;
import com.gitee.deeround.jdbchelper.out.DbTable;
import com.gitee.deeround.jdbchelper.out.PageList;
import com.gitee.deeround.jdbchelper.resultSetExtractors.CustomApply;
import org.springframework.jdbc.core.JdbcTemplate;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

public class DbActionImpl implements DbAction {


    private final DbActionQuery dbActionQuery;
    private final DbActionExecute dbActionExecute;
    private final DbActionDdl dbActionDdl;
    private final DbActionFunc dbActionFunc;
    private final DbActionExt dbActionExt;

    public DbActionImpl(JdbcTemplate jdbcTemplate) {
        this.dbActionQuery = new DbActionQueryImpl(jdbcTemplate);
        this.dbActionExecute = new DbActionExecuteImpl(jdbcTemplate);
        this.dbActionDdl = new DbActionDdlImpl(jdbcTemplate, this.dbActionQuery);
        this.dbActionFunc = new DbActionFuncImpl(jdbcTemplate);
        this.dbActionExt = new DbActionExtImpl(jdbcTemplate);
    }

    @Override
    public boolean existsTable(String tableName) {
        return dbActionDdl.existsTable(tableName);
    }

    @Override
    public boolean existsTableColumn(String tableName, String columnName) {
        return dbActionDdl.existsTableColumn(tableName, columnName);
    }

    @Override
    public void createTable(DbTable dbTable) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.createTable(dbTable);
    }

    @Override
    public void dropTable(String tableName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.dropTable(tableName);
    }

    @Override
    public void copyTable(String tableName, String newTableName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.copyTable(tableName, newTableName);
    }

    @Override
    public void addTableColumn(DbColumn dbColumn) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.addTableColumn(dbColumn);
    }

    @Override
    public void modifyTableColumn(DbColumn dbColumn) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.modifyTableColumn(dbColumn);
    }

    @Override
    public void removeTableColumn(String tableName, String columnName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.removeTableColumn(tableName, columnName);
    }


    @Override
    public void addPrimaryKey(String tableName, String columnName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.addPrimaryKey(tableName, columnName);
    }

    @Override
    public void addPrimaryKey(String tableName, List<String> columnName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.addPrimaryKey(tableName, columnName);
    }

    @Override
    public void removePrimaryKey(String tableName) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.removePrimaryKey(tableName);
    }

    @Override
    public void addIndex(String tableName, String columnName, String indexName, boolean isUnique) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.addIndex(tableName, columnName, indexName, isUnique);
    }

    @Override
    public void addIndex(String tableName, List<String> columnName, String indexName, boolean isUnique) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionDdl.addIndex(tableName, columnName, indexName, isUnique);
    }

    @Override
    public int execute(String sql) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.execute(sql);
    }

    @Override
    public int execute(String sql, List<SqlParameter> args) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.execute(sql, args);
    }

    @Override
    public int[] batchExecute(List<String> sqls) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.batchExecute(sqls);
    }

    @Override
    public int delete(String tableName, String columnName, Object columnValue) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.delete(tableName, columnName, columnValue);
    }

    @Override
    public int delete(String tableName, String columnName, List<Object> columnValue) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.delete(tableName, columnName, columnValue);
    }

    @Override
    public int update(String sql) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.update(sql);
    }

    @Override
    public int update(String sql, Object[] args) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.update(sql, args);
    }

    @Override
    public int[] batchUpdate(List<String> sqls) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.batchUpdate(sqls);
    }

    @Override
    public int[] batchUpdate(List<String> sqls, int batch) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.batchUpdate(sqls, batch);
    }

    @Override
    public int[] batchUpdate(String sql, List<Object[]> args) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.batchUpdate(sql, args);
    }

    @Override
    public int[] batchUpdate(String sql, List<Object[]> args, int batch) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        return dbActionExecute.batchUpdate(sql, args, batch);
    }

    @Override
    public void mergeInto(String tableName, String newData, String idColumn, List<String> insertColumns, List<String> updateColumns) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionExt.mergeInto(tableName, newData, idColumn, insertColumns, updateColumns);
    }

    @Override
    public void mergeInto(String tableName, String newData, String idColumn, List<String> insertColumns, List<String> updateColumns, Object[] ps) {
        if (DbActionConfig.readonly) {
            throw new DbException("只读模式，无法完成此操作");
        }
        if (DbActionConfig.writeMaxNum > 0) {
            if (DbActionConfig.writeNum.longValue() > DbActionConfig.writeMaxNum) {
                throw new DbException("写操作已达上线，无法完成此操作");
            }
            DbActionConfig.writeNum.increment();
        }
        dbActionExt.mergeInto(tableName, newData, idColumn, insertColumns, updateColumns, ps);
    }

    @Override
    public String recursiveSub(String tableName, String idColumn, String pidColumn, List<String> columns, String idValue) {
        return dbActionExt.recursiveSub(tableName, idColumn, pidColumn, columns, idValue);
    }

    @Override
    public String funDate() {
        return dbActionFunc.funDate();
    }

    @Override
    public String funTimestamp() {
        return dbActionFunc.funTimestamp();
    }

    @Override
    public String funGuid() {
        return dbActionFunc.funGuid();
    }

    @Override
    public String funWmConcat(String columnName) {
        return dbActionFunc.funWmConcat(columnName);
    }

    @Override
    public DataTable queryForDataTable(String sql) {
        return dbActionQuery.queryForDataTable(sql);
    }

    @Override
    public DataTable queryForDataTable(String sql, Object[] args) {
        return dbActionQuery.queryForDataTable(sql, args);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql) {
        return dbActionQuery.queryForList(sql);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql, Object[] args) {
        return dbActionQuery.queryForList(sql, args);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Class<T> elementType) {
        return dbActionQuery.queryForListObject(sql, elementType);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Object[] args, Class<T> elementType) {
        return dbActionQuery.queryForListObject(sql, args, elementType);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, CustomApply<T> customApply) {
        return dbActionQuery.queryForListObject(sql, customApply);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Object[] args, CustomApply<T> customApply) {
        return dbActionQuery.queryForListObject(sql, args, customApply);
    }

    @Override
    public Map queryForMap(String sql) {
        return dbActionQuery.queryForMap(sql);
    }

    @Override
    public Map queryForMap(String sql, Object[] args) {
        return dbActionQuery.queryForMap(sql, args);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> elementType) {
        return dbActionQuery.queryForObject(sql, elementType);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, Class<T> elementType) {
        return dbActionQuery.queryForObject(sql, args, elementType);
    }

    @Override
    public <T> T queryForObject(String sql, CustomApply<T> customApply) {
        return dbActionQuery.queryForObject(sql, customApply);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, CustomApply<T> customApply) {
        return dbActionQuery.queryForObject(sql, args, customApply);
    }

    @Override
    public Object queryForValue(String sql) {
        return dbActionQuery.queryForValue(sql);
    }

    @Override
    public Object queryForValue(String sql, Object[] args) {
        return dbActionQuery.queryForValue(sql, args);
    }

    @Override
    public String queryForString(String sql) {
        return dbActionQuery.queryForString(sql);
    }

    @Override
    public String queryForString(String sql, Object[] args) {
        return dbActionQuery.queryForString(sql, args);
    }

    @Override
    public Integer queryForInteger(String sql) {
        return dbActionQuery.queryForInteger(sql);
    }

    @Override
    public Integer queryForInteger(String sql, Object[] args) {
        return dbActionQuery.queryForInteger(sql, args);
    }

    @Override
    public BigDecimal queryForDecimal(String sql) {
        return dbActionQuery.queryForDecimal(sql);
    }

    @Override
    public BigDecimal queryForDecimal(String sql, Object[] args) {
        return dbActionQuery.queryForDecimal(sql, args);
    }

    @Override
    public PageList<Map<String, Object>> queryForPage(String sql, int pageNum, int pageSize) {
        return dbActionQuery.queryForPage(sql, pageNum, pageSize);
    }

    @Override
    public PageList<Map<String, Object>> queryForPage(String sql, Object[] args, int pageNum, int pageSize) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, Class<T> elementType) {
        return dbActionQuery.queryForPage(sql, pageNum, pageSize, elementType);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, Object[] args, int pageNum, int pageSize, Class<T> elementType) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize, elementType);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, CustomApply<T> customApply) {
        return dbActionQuery.queryForPage(sql, pageNum, pageSize, customApply);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, Object[] args, int pageNum, int pageSize, CustomApply<T> customApply) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize, customApply);
    }

    @Override
    public String getPageSql(String sql, int pageNum, int pageSize) {
        return dbActionQuery.getPageSql(sql, pageNum, pageSize);
    }


    //以下为扩展查询方法，目的是为了方便传参


    @Override
    public <T> List<T> queryForListObject(String sql, Class<T> elementType, Object... args) {
        return dbActionQuery.queryForListObject(sql, args, elementType);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, CustomApply<T> customApply, Object... args) {
        return dbActionQuery.queryForListObject(sql, args, customApply);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> elementType, Object... args) {
        return dbActionQuery.queryForObject(sql, args, elementType);
    }

    @Override
    public <T> T queryForObject(String sql, CustomApply<T> customApply, Object... args) {
        return dbActionQuery.queryForObject(sql, args, customApply);
    }

    @Override
    public PageList<Map<String, Object>> queryForPage(String sql, int pageNum, int pageSize, Object... args) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, Class<T> elementType, Object... args) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize, elementType);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, CustomApply<T> customApply, Object... args) {
        return dbActionQuery.queryForPage(sql, args, pageNum, pageSize, customApply);
    }
}
